package com.sjsu.cloudmanager.server.service;

import com.extjs.gxt.ui.client.data.BasePagingLoadResult;
import com.extjs.gxt.ui.client.data.BasePagingLoader;
import com.extjs.gxt.ui.client.data.PagingLoadConfig;
import com.extjs.gxt.ui.client.data.PagingLoadResult;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.sjsu.cloudmanager.client.service.CloudLabService;
import com.sjsu.cloudmanager.client.ui.model.CloudLabBean;
import com.sjsu.cloudmanager.client.ui.model.ComputingMachineBean;
import com.sjsu.cloudmanager.dao.CloudLabDao;
import com.sjsu.cloudmanager.model.*;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;


import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * cloud lab service impl
 * User: ckempaiah
 * Date: 9/21/11
 * Time: 12:14 AM
 * To change this template use File | Settings | File Templates.
 */
public class CloudLabServiceImpl extends RemoteServiceServlet implements CloudLabService {
    private static final Log log = LogFactory.getLog(CloudLabServiceImpl.class);

    private CloudLabDao cloudLabDao;
    private CloudManager cloudManager;

    @Override
    public Integer createCloudLab(String labName, String status) {

        return cloudLabDao.createCloudLab(labName, status);
    }

    @Override
    public Integer addComputingMachine(Integer labId, String machineName, String operatingSystem, int memory, String osVersion) {

        CloudLab cloudLab = cloudLabDao.getCloudLab(labId);

        ComputingMachine computingMachine = new ComputingMachine();

        computingMachine.setCloudLab(cloudLab);
        computingMachine.setMachineName(machineName);
        computingMachine.setOperatingSystem(operatingSystem);
        computingMachine.setOperatingSystemVersion(osVersion);
        computingMachine.setMemory(memory);
        cloudLabDao.saveOrUpdate(computingMachine);
        return computingMachine.getMachineId();
    }

    @Override
    public void addMachineSoftware(Integer machineId, List<Integer> softwareIdList) {

        ComputingMachine computingMachine = cloudLabDao.getComputingMachine(machineId);

        if (CollectionUtils.isNotEmpty(softwareIdList)) {
            Set<MachineSoftware> machineSoftwareSet = new HashSet<MachineSoftware>();
            for (Integer softwareId : softwareIdList) {

                MachineSoftware machineSoftware = new MachineSoftware();
                machineSoftware.setComputingMachine(computingMachine);
                Software software = cloudLabDao.getCloudSoftware(softwareId);
                machineSoftware.setSoftware(software);
                machineSoftwareSet.add(machineSoftware);
            }
            computingMachine.setMachineSoftware(machineSoftwareSet);
            cloudLabDao.saveOrUpdate(computingMachine);
        }

    }

    //injected beans
    public CloudLabDao getCloudLabDao() {
        return cloudLabDao;
    }

    public void setCloudLabDao(CloudLabDao cloudLabDao) {
        this.cloudLabDao = cloudLabDao;
    }

    @Override
    public ComputingMachine getComputingMachine(Integer machineId) {
        return cloudLabDao.getComputingMachine(machineId);
    }

    @Override
    public CloudLab getCloudLab(Integer labId) {
        return cloudLabDao.getCloudLab(labId);
    }

    @Override
    public void removeCloudLab(Integer cloudLabId) {
        CloudLab cloudLab = cloudLabDao.getCloudLab(cloudLabId);

        cloudLabDao.removeCloudLab(cloudLab);
    }

    @Override
    public void removeComputingMachine(Integer machineId) {
        ComputingMachine computingMachine = cloudLabDao.getComputingMachine(machineId);
        cloudLabDao.removeComputingMachine(computingMachine);
    }

    @Override
    public List<ComputingMachine> findComputingMachines(Integer labId) {
        return cloudLabDao.findComputingMachines(labId);
    }

    @Override
    public List<CloudLab> getCloudLabs() {
        return cloudLabDao.getCloudLabs();
    }


    /**
     * returns beans that are specific to UI
     *
     * @return
     */
    public BasePagingLoadResult<CloudLabBean> getCloudLabBeans(PagingLoadConfig pagingLoadConfig) {
        BasePagingLoadResult<CloudLabBean> pagingLoadResult = null;
        List<CloudLab> cloudLabList = cloudLabDao.getCloudLabs();

        if (CollectionUtils.isNotEmpty(cloudLabList)) {
            List<CloudLabBean> cloudLabBeanList = new ArrayList<CloudLabBean>();
            for (CloudLab cloudLab : cloudLabList) {

                cloudLabBeanList.add(new CloudLabBean(cloudLab.getLabName(), cloudLab.getLabStatus()));
            }

            pagingLoadResult = new BasePagingLoadResult<CloudLabBean>(cloudLabBeanList, 0, cloudLabList.size());
        }

        return pagingLoadResult;
    }


    /**
     * returns beans that are specific to UI
     *
     * @return
     */
    public List<CloudLabBean> getCloudLabBeanList() {
        BasePagingLoadResult<CloudLabBean> pagingLoadResult = null;
        List<CloudLab> cloudLabList = cloudLabDao.getCloudLabs();
        List<CloudLabBean> cloudLabBeanList = null;

        if (CollectionUtils.isNotEmpty(cloudLabList)) {
            cloudLabBeanList = new ArrayList<CloudLabBean>();
            for (CloudLab cloudLab : cloudLabList) {

                cloudLabBeanList.add(new CloudLabBean(cloudLab.getLabId(), cloudLab.getLabName(), cloudLab.getLabStatus()));
            }
        }
        return cloudLabBeanList;
    }


    @Override
    public List<ComputingMachineBean> getComputingMachineBeanList() {

        List<ComputingMachine> machineList = cloudLabDao.getAllComputingMachines();
        List<ComputingMachineBean> computingBeanList = null;

        if (CollectionUtils.isNotEmpty(machineList)) {
            computingBeanList = new ArrayList<ComputingMachineBean>();
            for (ComputingMachine machine : machineList) {
//                CloudLabBean cloudLabBean = new CloudLabBean(machine.getCloudLab().getLabId()
//                        , machine.getCloudLab().getLabName(), machine.getCloudLab().getLabStatus());

                ComputingMachineBean computingMachineBean = new ComputingMachineBean(
                        machine.getMachineId(),
                        machine.getMachineName(),
                        machine.getMachineCloudId(),
                        machine.getOperatingSystem(),
                        machine.getCloudLab().getLabName(),
                        machine.getMemory());
//                computingMachineBean.setCloudLabBean(cloudLabBean);
                computingBeanList.add(computingMachineBean);
            }
        }
        return computingBeanList;

    }


    public void saveCloudLab(CloudLabBean cloudLabBean) {
        CloudLab cloudLab = new CloudLab();
        cloudLab.setLabName(cloudLabBean.getLabName());
        cloudLab.setLabId(cloudLabBean.getLabId());
        if (StringUtils.isBlank(cloudLabBean.getLabStatus())) {
            cloudLab.setLabStatus(LabStatus.saved.toString());
        } else {
            cloudLab.setLabStatus(cloudLabBean.getLabStatus());
        }
        cloudLabDao.saveOrUpdate(cloudLab);
    }

    public ComputingMachineBean getComputingMachineBean(Integer machineId) {
        ComputingMachine computingMachine = cloudLabDao.getComputingMachine(machineId);
        CloudLabBean cloudLabBean = new CloudLabBean(computingMachine.getCloudLab().getLabId()
                , computingMachine.getCloudLab().getLabName(), computingMachine.getCloudLab().getLabStatus());
        ComputingMachineBean computingMachineBean = new ComputingMachineBean(computingMachine.getMachineId()
                , computingMachine.getMachineName(), computingMachine.getMachineCloudId()
                , computingMachine.getOperatingSystem(), computingMachine.getCloudLab().getLabName(), computingMachine.getMemory());
        computingMachineBean.setLabId(computingMachine.getCloudLab().getLabId());
        computingMachineBean.setCloudLabBean(cloudLabBean);

        //TODO: set list of available softwares
        return computingMachineBean;

    }

    public void saveCloudResource(ComputingMachineBean computingMachineBean) {
        ComputingMachine computingMachine = null;
        if (computingMachineBean.getMachineId() != null && computingMachineBean.getMachineId() > 0) {
            computingMachine = cloudLabDao.getComputingMachine(computingMachineBean.getMachineId());
        } else {
            computingMachine = new ComputingMachine();
        }
        computingMachine.setMachineName(computingMachineBean.getMachineName());
        computingMachine.setMemory(computingMachineBean.getMemory());
        computingMachine.setOperatingSystem(computingMachineBean.getOperatingSystem());

        if (computingMachineBean.getCloudLabBean() != null) {
            CloudLab cloudLab = cloudLabDao.getCloudLab(computingMachineBean.getCloudLabBean().getLabId());
            computingMachine.setCloudLab(cloudLab);
        }
        cloudLabDao.saveOrUpdate(computingMachine);
    }

    public void setCloudManager(CloudManager cloudManager) {
        this.cloudManager = cloudManager;
    }

    public void startCloudResource(List<ComputingMachineBean> computingMachineBeanList) {
        for (ComputingMachineBean computingMachineBean : computingMachineBeanList) {
            ComputingMachine computingMachine = cloudLabDao.getComputingMachine(computingMachineBean.getMachineId());
            if (StringUtils.isNotBlank(computingMachine.getMachineCloudId())) {
                cloudManager.restartMachine(computingMachine);
            } else {
                cloudManager.createMachine(computingMachine);
            }
            cloudLabDao.saveOrUpdate(computingMachine);
        }
    }

    public void stopCloudResource(List<ComputingMachineBean> computingMachineBeanList) {
        for (ComputingMachineBean computingMachineBean : computingMachineBeanList) {
            ComputingMachine computingMachine = cloudLabDao.getComputingMachine(computingMachineBean.getMachineId());
            cloudManager.stopMachine(computingMachine);
        }
    }

    public void terminateCloudResource(List<ComputingMachineBean> computingMachineBeanList) {
        for (ComputingMachineBean computingMachineBean : computingMachineBeanList) {
            ComputingMachine computingMachine = cloudLabDao.getComputingMachine(computingMachineBean.getMachineId());
            cloudManager.deleteMachine(computingMachine);
            cloudLabDao.removeComputingMachine(computingMachine);
        }
    }

    public ComputingMachineBean getComputingMachineDescription(Integer machineId) {

        ComputingMachineBean computingMachineBean = null;
        ComputingMachine computingMachine = cloudLabDao.getComputingMachine(machineId);
        CloudLabBean cloudLabBean = new CloudLabBean(computingMachine.getCloudLab().getLabId()
                , computingMachine.getCloudLab().getLabName(), computingMachine.getCloudLab().getLabStatus());
        computingMachineBean = new ComputingMachineBean(computingMachine.getMachineId()
                , computingMachine.getMachineName(), computingMachine.getMachineCloudId()
                , computingMachine.getOperatingSystem(), computingMachine.getCloudLab().getLabName(), computingMachine.getMemory());
        computingMachineBean.setLabId(computingMachine.getCloudLab().getLabId());
        computingMachineBean.setCloudLabBean(cloudLabBean);

        if (StringUtils.isNotBlank(computingMachine.getMachineCloudId())) {
            try {
                ComputingMachineDescription machineDescription = cloudManager.getMachineDescription(computingMachine);
                computingMachineBean.setLaunchTime(machineDescription.getLaunchTime());
                computingMachineBean.setPublicDns(machineDescription.getPublicDns());
                computingMachineBean.setImageId(machineDescription.getImageId());
                computingMachineBean.setStatus(machineDescription.getStatus());
            } catch (CloudServiceException cse) {
                log.error("Cloud Service exception", cse);
            }
        }
        return computingMachineBean;
    }
}
